package edu.uoc.tds.pec4.gestor.impl;

import edu.uoc.tds.pec4.gestor.GestorConexion;
import edu.uoc.tds.pec4.model.SS1_TipoEvento;
import edu.uoc.tds.pec4.model.SS2_Evento;
import edu.uoc.tds.pec4.model.SS4_Acceso;
import edu.uoc.tds.pec4.model.SS4_Checkin;
import edu.uoc.tds.pec4.model.SS4_DatosInscripcion;
import edu.uoc.tds.pec4.model.SS4_Inscripcion;
import edu.uoc.tds.pec4.util.ExceptionUtils;
import java.io.Serializable;
import java.rmi.RemoteException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * Tecnicas de Desarrollo de Software - (UOC)
 * Implementacion de la interfaz de definicion para el subsistema de conexion y reservas
 * @author Pedro Bauzá Picó
 * @version 1.0
 */
public class GestorConexionImpl extends GestorDiscoImpl implements GestorConexion, Serializable {

    public GestorConexionImpl() throws RemoteException {
    }

    /**
     * Metodo que comprueba el usuario y contraseña introducidos para el acceso al sistema
     * @param p_Loguin: Usuario introducido para el acceso al sistema
     * @param p_Contrasenya: Contraseña introducida para el acceso al sistema
     * @return Objeto Acceso: Objeto que se utilizara para almacenar los atributos necesarios en sesion
     */
    public SS4_Acceso comprobarLoguin(String p_Loguin, String p_Contrasenya) {
        SS4_Acceso acceso = null;
        ResultSet rs = null;
        try {
            conectaBD();
            String v_Tabla = "usuario";
            String v_Condicion = "loguin='" + p_Loguin + "' and contrasenya='" + p_Contrasenya + "' and activo='1'";
            String v_Campos = "cod_usuario,  tipo_usuario, rol, cod_centrodocente, nombre, apellido1, apellido2, loguin, contrasenya, ccc_banco, ccc_sucursal, ccc_dc, ccc_cuenta";
            rs = select(v_Tabla, v_Condicion, v_Campos);

            if (rs.next()) {
                acceso = new SS4_Acceso();
                acceso.setCod_usuario(rs.getInt("cod_usuario"));
                acceso.setTipo_usuario(rs.getInt("tipo_usuario"));
                acceso.setRol(rs.getInt("rol"));
                acceso.setCod_centro(rs.getInt("cod_centrodocente"));
                acceso.setNombre(rs.getString("nombre"));
                acceso.setApellido1(rs.getString("apellido1"));
                acceso.setApellido2(rs.getString("apellido2"));
                acceso.setLoguin(rs.getString("loguin"));
                acceso.setContrasenya(rs.getString("contrasenya"));
                acceso.setCcc_banco(rs.getString("ccc_banco"));
                acceso.setCcc_sucursal(rs.getString("ccc_sucursal"));
                acceso.setCcc_dc(rs.getString("ccc_dc"));
                acceso.setCcc_cuenta(rs.getString("ccc_cuenta"));
            }

        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            acceso = null;
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            acceso = null;
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return acceso;
    }

    /**
     * Metodo que realiza el cambio de contraseña
     * @param p_Cod_usuario: Codigo del usuario que realiza el cambio
     * @param p_Contrasenya: Nueva contraseña introducida para el cambio
     * @return Devolvemos el valor que nos retorna executeUpdate, que 1 ha ido correcto y otro valor es que ha ido incorrecto
     */
    public int cambiarContrasenya(int p_Cod_usuario, String p_Contrasenya) {
        try {
            conectaBD();
            String v_Tabla = "usuario";
            String v_Condicion = "cod_usuario=" + p_Cod_usuario;
            String v_Campos = "contrasenya='" + p_Contrasenya + "'";
            return update(v_Tabla, v_Condicion, v_Campos);
        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } finally {
            try {
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return 0;   //Significa que ha ido mal
    }

    /**
     * Metodo que consulta los tipos de eventos disponibles en la aplicacion
     * @return Lista de objetos tipo evento
     */
    public List<SS1_TipoEvento> getListaTipoEvento() {
        List<SS1_TipoEvento> lista = new ArrayList<SS1_TipoEvento>();
        ResultSet rs = null;
        try {
            conectaBD();
            String v_Tabla = "tipoevento";
            String v_Condicion = "activo='1'";
            String v_Campos = "cod_tipoevento, titulo";
            rs = select(v_Tabla, v_Condicion, v_Campos);

            while (rs.next()) {
                SS1_TipoEvento tipoEvento = new SS1_TipoEvento();
                tipoEvento.setId(rs.getInt("cod_tipoevento"));
                tipoEvento.setTitulo(rs.getString("titulo"));
                lista.add(tipoEvento);
            }

        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return lista;
    }

    /**
     * Metodo que consulta los eventos disponibles en la aplicacion, filtrando por tipo evento
     * @param p_TipoEvento: Parametro de tipo evento
     * @return Lista de objetos evento
     */
    public List<SS2_Evento> getListaEvento(String p_TipoEvento) {
        List<SS2_Evento> lista = new ArrayList<SS2_Evento>();
        ResultSet rs = null;
        try {
            conectaBD();
            String v_Tabla = "evento";
            String v_Condicion = "";
            if (!p_TipoEvento.equals("0")) {
                v_Condicion = " cod_tipoevento=" + p_TipoEvento;
            }
            String v_Campos = "cod_evento, descripcion";
            rs = select(v_Tabla, v_Condicion, v_Campos);

            while (rs.next()) {
                SS2_Evento evento = new SS2_Evento();
                evento.setidEvento(rs.getInt("cod_evento"));
                evento.setdescripcion(rs.getString("descripcion"));
                lista.add(evento);
            }

        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return lista;
    }

    /**
     * Metodo que consulta los elementos de checkIn por universidad, centro
     * @param p_TipoEvento: Parametro de tipo evento
     * @return Lista de objetos checkIn
     */
    public List<SS4_Checkin> getListaCheckIn(String p_TipoEvento) {
        List<SS4_Checkin> lista = new ArrayList<SS4_Checkin>();
        ResultSet rs = null;
        try {
            conectaBD();
            StringBuilder v_Sql = new StringBuilder();
            v_Sql.append("  Select	ins.cod_usuario, uni.nombre as universidad, cen.nombre as centro, usu.nombre as usuario, usu.apellido1, usu.apellido2, ins.fecha, ins.checkin ");
            v_Sql.append("  From	usuario usu, evento eve, universidad uni, centrodocente cen, inscripcion ins ");
            v_Sql.append("  Where	usu.cod_usuario = ins.cod_usuario  and	eve.cod_evento  = ins.cod_evento ");
            v_Sql.append("    and	eve.cod_centrodocente  = cen.cod_centrodocente  and	cen.cod_universidad = uni.cod_universidad ");
            v_Sql.append("    and	ins.cod_evento =" + p_TipoEvento);

            rs = selectQuery(v_Sql.toString());

            while (rs.next()) {
                SS4_Checkin checkin = new SS4_Checkin();
                checkin.setId_usuario(rs.getInt("cod_usuario"));
                checkin.setUniversidad(rs.getString("universidad"));
                checkin.setCentro(rs.getString("centro"));
                checkin.setNomUsuario(rs.getString("usuario"));
                checkin.setApe1Usuario(rs.getString("apellido1"));
                checkin.setApe2Usuario(rs.getString("apellido2"));
                checkin.setFechaInscripcion(rs.getDate("fecha"));
                checkin.setCheckin(rs.getBoolean("checkin"));
                lista.add(checkin);
            }

        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return lista;
    }

    /**
     * Metodo que actualiza los checkIn de los asistentes que han asistido a un evento
     * @param p_Lista: Lista de objeto del tipo inscripcion
     * @return Booleano que nos indica como ha ido la operacion
     */
    public Boolean setListaCheckIn(List<SS4_Inscripcion> p_Lista) {
        try {
            conectaBD();
            String v_Tabla = "inscripcion";
            String v_Condicion = "";
            String v_Campos = "";

            for (int i = 0; i < p_Lista.size(); i++) {
                SS4_Inscripcion inscripcion = p_Lista.get(i);
                v_Campos = "checkin=" + inscripcion.getCheckin().toString();
                v_Condicion = "cod_usuario=" + inscripcion.getId_usuario() + " and cod_evento=" + inscripcion.getId_evento();
                update(v_Tabla, v_Condicion, v_Campos);
            }

        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            return false;
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            return false;
        } finally {
            try {
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return true;
    }

    /**
     * Metodo que consulta los tipos de evento disponibles en la aplicacion, filtrando por rol
     * @param p_Rol: Rol del usuario que esta en sesion
     * @return Lista de objetos tipo evento
     */
    public List<SS1_TipoEvento> getListaTipoEvento(int p_Rol) {
        List<SS1_TipoEvento> lista = new ArrayList<SS1_TipoEvento>();
        ResultSet rs = null;
        try {
            conectaBD();
            StringBuilder v_Sql = new StringBuilder();
            v_Sql.append("  Select	eve.cod_tipoevento, eve.titulo ");
            v_Sql.append("  From	tipoevento eve, tipoevento_roles rol ");
            v_Sql.append("  Where	eve.cod_tipoevento=rol.cod_tipoevento and rol.rol=" + p_Rol + " and eve.activo='1'");

            rs = selectQuery(v_Sql.toString());

            while (rs.next()) {
                SS1_TipoEvento tipoEvento = new SS1_TipoEvento();
                tipoEvento.setId(rs.getInt("cod_tipoevento"));
                tipoEvento.setTitulo(rs.getString("titulo"));
                lista.add(tipoEvento);
            }

        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return lista;
    }

    /** 
     * Metodo que consulta los eventos disponibles en la aplicacion, filtrando por tipo evento, fechas y rol
     * @param p_TipoEvento: Tipo de evento
     * @param p_FecInicial: Fecha de inicio de la busqueda
     * @param p_FecFinal: Fecha de fin de la busqueda
     * @param p_Rol: Rol del usuario que esta en sesion
     * @return Lista de objetos tipo evento
     */
    public List<SS2_Evento> getListaEvento(String p_TipoEvento, String p_FecInicial, String p_FecFinal, int p_Rol) {
        List<SS2_Evento> lista = new ArrayList<SS2_Evento>();
        ResultSet rs = null;
        try {
            conectaBD();
            StringBuilder v_Sql = new StringBuilder();
            v_Sql.append("  Select	eve.cod_evento, eve.nombre ");
            v_Sql.append("  From	evento eve, evento_roles rol ");
            v_Sql.append("  Where	eve.cod_evento = rol.cod_evento and rol.rol=" + p_Rol);
            v_Sql.append("    and	(eve.fecha_celebracion >=to_date('" + p_FecInicial + "', 'dd/MM/yyyy') and  eve.fecha_celebracion <=to_date('" + p_FecFinal + "', 'dd/MM/yyyy'))");
            v_Sql.append("    and       eve.cod_tipoevento=" + p_TipoEvento);

            rs = selectQuery(v_Sql.toString());

            while (rs.next()) {
                SS2_Evento evento = new SS2_Evento();
                evento.setidEvento(rs.getInt("cod_evento"));
                evento.setdescripcion(rs.getString("nombre"));
                lista.add(evento);
            }

        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
            lista = null;
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return lista;
    }

    /**
     * Metodo que consultara los datos necesarios para visualizar la informacion sobre el evento para inscribirse
     * @param p_Id_Evento: Evento
     * @param p_Rol: Rol del usuario que esta en sesion
     * @return Objetos que contendra los datos de la inscripcion
     */
    public SS4_DatosInscripcion getDatosInscripcion(String p_Id_Evento) {
        SS4_DatosInscripcion datosInscripcion = new SS4_DatosInscripcion();
        List<SS2_Evento> lista = new ArrayList<SS2_Evento>();
        ResultSet rs = null;
        try {
            conectaBD();
            StringBuilder v_Sql = new StringBuilder();
            v_Sql.append("  Select  eve.cod_evento, eve.fecha_celebracion, eve.fechainicioinscripcion, eve.fechafininscripcion,  eve.descripcion, eve.precio, eve.plazas,  ");
            v_Sql.append("          uni.nombre as universidad, cen.nombre as centro, cen.localidad, cen.direccion, cen.telefono ");
            v_Sql.append("  From    evento eve, universidad uni, centrodocente cen  ");
            v_Sql.append("  Where   eve.cod_centrodocente = cen.cod_centrodocente and cen.cod_universidad   = uni.cod_universidad and eve.cod_evento =" + p_Id_Evento);
            rs = selectQuery(v_Sql.toString());

            if (rs.next()) {
                //Datos sobre el evento
                datosInscripcion.setCod_Evento(rs.getInt("cod_evento"));
                datosInscripcion.setFecha(rs.getDate("fecha_celebracion"));
                datosInscripcion.setFechainicioinscripcion(rs.getDate("fechainicioinscripcion"));
                datosInscripcion.setFechafininscripcion(rs.getDate("fechafininscripcion"));
                datosInscripcion.setDescripcion(rs.getString("descripcion"));
                datosInscripcion.setPrecio(rs.getInt("precio"));
                datosInscripcion.setNombreUniversidad(rs.getString("universidad"));
                datosInscripcion.setNombreCentro(rs.getString("centro"));
                datosInscripcion.setLocalidad(rs.getString("localidad"));
                datosInscripcion.setDomicilio(rs.getString("direccion"));
                datosInscripcion.setTelefono(rs.getString("telefono"));
                datosInscripcion.setPlazas(rs.getInt("plazas"));

                //Buscamos si tiene prerrequisitos
                v_Sql.delete(0, v_Sql.length());
                v_Sql.append("Select	eve.cod_evento, eve.nombre ");
                v_Sql.append("From	evento eve ");
                v_Sql.append("Where	eve.cod_evento in(Select per.cod_prerrequisito From evento_prerrequisito per Where per.cod_evento="+ p_Id_Evento +")");

                rs = selectQuery(v_Sql.toString());
                while (rs.next()) {
                    SS2_Evento evento = new SS2_Evento();
                    evento.setidEvento(rs.getInt("cod_evento"));
                    evento.setNombre(rs.getString("nombre"));
                    lista.add(evento);
                }
                datosInscripcion.setPrerrequisito(lista);

                //Buscamos cuantas personas hay inscritas al evento
                v_Sql.delete(0, v_Sql.length());
                v_Sql.append("Select count(*) as inscritos From inscripcion Where cod_evento=" + p_Id_Evento);
                rs = selectQuery(v_Sql.toString());
                if (rs.next()) {
                    datosInscripcion.setInscritos(rs.getInt("inscritos"));
                }
            }

        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return datosInscripcion;
    }

    /**
     * Metodo que comprueba que dado un evento y usuario, ya exista una inscripcion
     * @param p_Id_Evento: Evento
     * @param p_Usuario: Codigo de usuario
     * @return Boolean que nos indica si esta o no inscrito un usuario a un evento
     */
    public Boolean getEstarInscrito(String p_Id_Evento, int p_Usuario) {
        ResultSet rs = null;
        Boolean v_EstarInscrito = false;
        try {
            conectaBD();
            String v_Tabla = "inscripcion";
            String v_Condicion = "cod_evento=" + p_Id_Evento + " and cod_usuario=" + p_Usuario;
            String v_Campos = "cod_evento, cod_usuario";
            rs = select(v_Tabla, v_Condicion, v_Campos);

            if (rs.next()) {
                v_EstarInscrito = true;
            }
        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return v_EstarInscrito;
    }

    /**
     * Metodo que comprueba que dado una lista de eventos prerrequisitos y un usuario, si ha asistido a todos los prerrequisitos
     * @param p_Lista: Lista de los eventos que son prerrequisitos para inscribirse a un evento
     * @param p_Usuario: Codigo de usuario
     * @return Boolean que nos indica si ha asistido o no a todos los prerrequisitos
     */
    public Boolean getAsistidoEvento(List<SS2_Evento> p_Lista, int p_Usuario) {
        SS2_Evento v_Evento = null;
        //Recorremos evento a evento y comprobamos si ha asistido
        for (int i = 0; i < p_Lista.size(); i++) {
            v_Evento = p_Lista.get(i);
            if (!getAsistirEvento(v_Evento.getidEvento(), p_Usuario)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Metodo que comprueba que dado un usuario y evento, el usuario ha asistido a dicho evento
     * @param p_Id_Evento: Codigo de evento
     * @param p_Usuario: Codigo de usuario
     * @return Boolean que nos indica si ha asistido o no
     */
    public Boolean getAsistirEvento(int p_Id_Evento, int p_Usuario) {
        ResultSet rs = null;
        Boolean v_AsistirEvento = false;
        try {
            conectaBD();
            String v_Tabla = "INSCRIPCION";
            String v_Condicion = "cod_evento=" + p_Id_Evento + " and cod_usuario=" + p_Usuario + " and checkin=true";
            String v_Campos = "cod_evento, cod_usuario";
            rs = select(v_Tabla, v_Condicion, v_Campos);

            if (rs.next()) {
                v_AsistirEvento = true;
            }
        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return v_AsistirEvento;
    }

    /**
     * Metodo que realiza la insercion de registros de inscripcion
     * @param p_Inscripcion: Objeto con los datos de la inscripcion
     * @return Valor numerico que retorna las filas insertadas
     */
    public int insertInscripcion(SS4_Inscripcion p_Inscripcion) {
        try {
            conectaBD();
            String v_Tabla = "INSCRIPCION";
            String v_Valores = p_Inscripcion.getId_evento() + "," + p_Inscripcion.getId_usuario() + ",'" + p_Inscripcion.getFecha_inscripcion() + "', false";
            String v_Campos = "cod_evento, cod_usuario, fecha, checkin";
            return insert(v_Tabla, v_Valores, v_Campos);
        } catch (SQLException ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } catch (Exception ex) {
            ExceptionUtils.visualizarError(ex.getMessage());
        } finally {
            try {
                desconectaBD();
            } catch (Exception e) {
            }
        }
        return 0;
    }
}
